package com.tedu.api.io;

import org.directwebremoting.json.JsonUtil;
import org.junit.jupiter.api.Test;
import java.io.*;

/** IO流：传输数据
 * File文件，文件夹类：无法读写数据
 * RandomAccessFile：读写按照字节，读写类不明确，靠构造器传入第二个参数确定
 *
 * Java 提出一套 标准 IO--读写单独提供类
 * 1.方向区别：
 * 输入流---（读：针对文件，文件往程序中走，文件’相对于程序‘）
 * 输出流---（写：针对文件，  文件写出  ，文件’相对于程序‘）
 * 输入流和输出流创建方式
 * 输入流 InputStream（抽象类）---顶级父类---读操作
 * 输出流 OutputStream（抽象类）---顶级父类---写操作
 * 以上两个六定义所有流具备读写操作，本身无法实例化
 * 2.按照功能进行区别
 * 低级流：专门搬运数据的流【叫做节点流】
 * FileInputStream  文件输入流：读操作  --InputStream(抽象类)
 * OutputStream     文件输出流：写操作  --OutputStream(抽象类)
 * 功能：建立在程序与数据源之间的”管道“，所有数据传输通过低级流【节点流】
 * 高级流：不能独立存在的流【处理流】
 *        处理低级流的数据，并且可以被其他高级流所处理！
 *        理解：处理搬运数据的流【高级流中类比较多】
 * ----------------流：明确功能，创建对象：直接使用低级流---高级流创建
 * 项目：  聊天室  Version  1  IO流：针对传字符串
 */
public class IOAPI {
   @Test
    public void testIOAPI() throws IOException {
       //创建标准IO流，方向划分：输入流与输出流--功能：低级流【节点流】
       //需求：从项目中写出”fox.txt“ 低级流：FileOutputStream
       //创建文件输出流 ---构造器("相对路径+文件全程")
       // 抛出异常FileNotFoundException：没有文件的异常
       // 原因：路径或者文件名写错
       FileOutputStream fos=new FileOutputStream("fos.txt",true);
       try {
           /**
            * 输出一句话：我们
            * write(字符串)   返回值：void
            * 作用：写出一个文件内容：字节数组
            * 抛出异常   IOException  IO流异常
            */
           //String 字符串  方法：getBytes()  可以将字符串转换成字符数组
           fos.write("樱花开放".getBytes());
           //标准IO流必须关闭
           fos.close(); //释放流：避免内存占用
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           if(fos!=null)
               try {
                   fos.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
       }
   }
    /**
     * FileOutputStream实现类---构造器使用方法
     * new FileOutputStream(String path,boolean append)
     * 通过第二个参数，确定数据是否追加，true代表追加，反之
     * new FileOutputStream(File file,boolean append);
     */
    @Test
    public void testIOA() throws IOException {
        //当前 API 项目 下添加 fos.txt--增加功能：追加效果
        //相对路径： ./fos.txt   直接写文件 不写./
        FileOutputStream fos=
                new FileOutputStream("fos.txt",true);
                String str="我要抓住未来";
                fos.write(str.getBytes());
                //关闭流
                fos.close();
    }

    /**低级流
     * 文件输入流FileInputStream
     * read()  返回值：int
     * 作用： 读取到一个字节
     */
    @Test
    public void testInputStream() throws IOException {
        //创建文件输入流----读入
        FileInputStream fis=
                new FileInputStream("fos.txt");
    //10KB  字节数组
        byte[] bytes=new byte[1024*10];
        //10KB 读数据【不想看到整数值】
        int len=fis.read(bytes);
        //String 字符串类--提供构造器方法： 按照字节数组量，输出字符串
        //String 构造器 new String(字节数组，开始读取文件，结束读取文件);
        //将【二进制】证书 转换为字符串
        String str=new String(bytes,0,len);//循环
        //一次性将给定好的字节数组【10KB】写入到文件中
        System.out.println("打印读："+str);
        fis.close();
    }
    //需求：重构RandomAccessFile类--复制视频的方法
    @Test
    public void testWork() throws IOException {
        //1.创建输入流---读---被复制文件【源文件】
        FileInputStream fis=new FileInputStream("2023冠军.mp3");
        //2.创建输出流----写---复制品
        FileOutputStream fos=new FileOutputStream("标准IO.mp3");
        //3.用于保存读取到的字节量
        int len=-1; //①保存读取的数据值【可以被覆盖】②-1代表文件结尾
        //6.视频空间大，解决方案：10KB，字节数组：设定保存值10KB
        byte[] bytes=new byte[1024*10];
        //4.一直都去文件，保存len中，如果结果不等于-1，一直读
        //(len=fis.read(bytes))!=-1
        long start=System.currentTimeMillis();//毫秒数
        while((len=fis.read(bytes))!=-1){
            //4.1 将读取到的【10KB】文件写出
            fos.write(bytes,0,len);
        }
        long end=System.currentTimeMillis();//结束毫秒数
        System.out.println("测试传输时间"+(end-start)+"毫秒");
        //5.关闭流
        fis.close();
        fos.close();

    }
    /**
     * 高级流【处理流】：处理低级流以及其他高级流的一种流
     * 高级六不能独立存在，一定处理低级流
     * BufferedInputStream --- 高级流：快速读    缓冲输入流
     * BufferedOutputStream -- 高级流：快速写    缓冲输出流
     * 以上两个高级流，内嵌一套按照实际传输数据大小，随机型改变的字节数组
     * 高级流语法：
     * BufferedInputStream bis=new BufferedInputStream(低级流引用);
     * 需求：视频 使用IO流【低级流+高级流】--实现视频快速复制
     */
    @Test
    public void testCV() throws IOException {
        //创建低级流：输入流:高级流，输出流：高级流
        FileInputStream fis=new FileInputStream("2023冠军.mp3");
        BufferedInputStream bis=new BufferedInputStream(fis);

        FileOutputStream fos=new FileOutputStream("缓冲文件.mp3");
        BufferedOutputStream bos=new BufferedOutputStream(fos);
        //2.定义整数变量保存每次读取的字节量
         int len=-1;
         //3.将高级流：缓冲输入流--读取的数据---保存给交len，结果不等于-1
        // (len=bis.read())!=-1
        long start=System.currentTimeMillis();
         while((len=bis.read())!=-1){
             //write() 写出【缓冲字符输出流：自动产生合理字节数组】 ---》读取
             bos.write(len);
         }
         long end= System.currentTimeMillis();
        System.out.println("缓冲流花费时间："+(end-start));
         //4.关闭流
        bos.close();
        fis.close();

    }
    /**
     * [高级流：处理流]
     * BufferedOutputStream 缓冲输出流
     * 需求：写出一份文件：bos.txt，写出：一段文本内容
     * 所有的流，全部都不是正确的写法：IO流异常最多，采取捕获异常并作出处理
     */
    @Test
    public void testBOS() throws IOException {
        //创建低级流--写出bos.txt
        FileOutputStream fos=new FileOutputStream("bos.txt");
        //创建高级流--写出 一段文本内容[缓冲区:字节数组]
        BufferedOutputStream bos=new BufferedOutputStream(fos);
        String str="学的越多，不会的就越多";
        //write(byte[] b) 作用：写出字节数组
        bos.write(str.getBytes());
        /**
         *     str数据量小      缓冲区大    强制送出
         *        45人         车  100    晚上 9
         * flush()
         * 作用：可以强制将内部缓冲区数据一次性读写
         * 缺点：频繁使用flush降低读写
         */
        //bos.flush();
        bos.close();
        fos.close();
    }
    /**
     * 标准IO 必须与 异常 存在 ---”传输数据“保障数据安全【处理异常】
     * 异常重点：1.认识代码中抛出异常【查看API】，异常产生原因！
     *         2.异常处理---【快捷键：ctrl+alt+T】  ++核心++
     *         语法：try{
     *         怀疑可能有错误或者已经提示异常
     *         }catch(异常名称 e){
     *             e.print();   //打印异常信息---通过异常信息解决问题
     *         }catch(中异常名 e){ catch可以捕获很多异常：小到大
     *         }
     *         finally{
     *             一定执行代码块
     *         }
     *   --------------------------------------------
     *     异常大小问题：
     *     IO流：FileNotFoundException>IOException
     *     Exception顶级父类
     *   --------------------------------------------
     *
     *   低级流：FileOutputStream 文件输出流---写出
     *          FileInputStream  文件输入流---读入
     *   高级流：BufferedOutputStream 缓冲输出流---写出--功能：缓冲区
     *          BufferedInputStream 缓冲输入流---读入---功能：缓冲区
     *
     *   考试题：      final与finally的区别  ⭐⭐⭐
     *           final关键字：修饰 变量，方法，类--》变量成常量
     *                                          方法不能重写
     *                                          类不能被继承
     *           finally关键字：异常处理机制中：捕获异常
     *           finally在捕获一场中，可以写，也可以不写
     *           所有异常都不符合，一定会执行的语法块
     *           通常使用在IO流中：关闭流为主!关闭高级流--》简介关闭低级流
     *
     *           需求：BOS高级流---重新结合异常---》标准IO流
     */
    @Test
    public void testBOSIO() throws IOException {
        //1.需要将流置空---1.覆盖，不用多次创建对象！2.关闭流
        FileOutputStream fos=null;       //低级流--搬运数据：写出
        BufferedOutputStream bos=null;  //高级流--处理低级流：缓冲数据流
        //2.捕获异常操作：快捷键alt+ctrl+T：怀疑IO流代码
        //2.1创建输出流
        try {
            fos=new FileOutputStream("BOS标准流写法.txt");
            bos=new BufferedOutputStream(fos);
            //3.高级流：缓冲输出流---功能：缓冲区【字节数组】 写出数据
            bos.write("标准流写法".getBytes());
            //4.缓冲区:数据量比较小---采用flush()  数据一次性写出
            bos.flush();
        } catch (FileNotFoundException e){
            e.printStackTrace(); //打印异常信息：路径写错，文件不存在
            System.out.println("【小】文件不存在异常");
        }catch (IOException e) { //IO流最大的 异常：小异常不处理
            e.printStackTrace();
            System.out.println("【中】IO流异常");
        }catch (Exception e) {
            e.printStackTrace();
            System.out.println("【大】异常");
        } finally {
            //一定执行代码块：IO流关闭--高级流--关闭高级六--低级流关闭【捕获异常】
            //                      低级流---关闭低级流【捕获异常】
            //5.先判断，高级流---是否为空【有没有高级流对象】---有高级流对象【必须关闭】
            //                                          没有高级流对象【不必关闭】
            if(bos!=null)
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
